package org.ehe.business.drawing.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.ehe.business.drawing.domain.dto.PDFExtractInfoDTO;
import org.ehe.common.core.service.OssService;
import org.ehe.system.domain.vo.SysOssVo;
import org.ehe.system.service.ISysOssService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.InputStream;

/**
 * PDF信息提取服务 - 优化版
 * @author :zhangnn
 * @className :PDFExtractorService
 * @description: 专门针对工程图纸PDF的信息提取
 * @date 2025-08-29 13:37:20
 */

@Slf4j
@Service
@RequiredArgsConstructor
public class PDFExtractorService {

    private final ISysOssService ossService;

    /**
     * 从PDF文件中提取图纸信息
     * @param file PDF文件
     * @return 提取的图纸信息
     */
    public PDFExtractInfoDTO extractDrawingInfo(MultipartFile file) {
        PDFExtractInfoDTO result = new PDFExtractInfoDTO();

        try {
            PDDocument document = loadPDDocument(file);

            try {
                PDFTextStripper stripper = new PDFTextStripper();
                String text = stripper.getText(document);

                log.info("PDF文件内容提取完成，文本长度: {}", text.length());
                log.debug("PDF内容预览: {}", text.substring(0, Math.min(text.length(), 500)));

                // 预处理文本，统一格式
                String cleanText = preprocessText(text);
                log.debug("清理后的文本预览: {}", cleanText.substring(0, Math.min(cleanText.length(), 500)));

                // 提取各种信息
                extractDrawingNumber(cleanText, result);
                extractCode(cleanText, result);
                extractName(cleanText, result);
                extractDesigner(cleanText, result);
                extractDates(cleanText, result);
                extractMaterial(cleanText, result);
                extractWeight(cleanText, result);
                extractApproverAndChecker(cleanText, result);
                extractRevision(cleanText, result);
                extractTechnicalRequirements(cleanText, result);

                log.info("PDF信息提取完成: {}", result);

            } finally {
                document.close();
            }

        } catch (IOException e) {
            log.error("PDF文件解析失败: {}", e.getMessage(), e);
            throw new RuntimeException("PDF文件解析失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("PDF信息提取过程中发生错误: {}", e.getMessage(), e);
            throw new RuntimeException("PDF信息提取失败: " + e.getMessage());
        }
        //文件上传
        SysOssVo upload = ossService.upload(file);
        result.setAttachmentId(upload.getOssId());

        return result;
    }

    /**
     * 文本预处理 - 统一格式，便于正则匹配
     */
    private String preprocessText(String text) {
        if (text == null) return "";

        // 统一空白字符
        String processed = text.replaceAll("\\r\\n", " ")
            .replaceAll("\\n", " ")
            .replaceAll("\\r", " ")
            .replaceAll("\\s+", " ")
            .trim();

        return processed;
    }

    /**
     * 根据PDFBox版本加载PDF文档
     */
    private PDDocument loadPDDocument(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();

        try {
            return PDDocument.load(inputStream);
        } catch (NoSuchMethodError e) {
            try {
                inputStream.close();
                inputStream = file.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                return PDDocument.load(bytes);
            } catch (Exception ex) {
                log.error("无法加载PDF文档，尝试的方法都失败了", ex);
                throw new IOException("不支持的PDFBox版本或PDF文件损坏", ex);
            }
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.warn("关闭输入流失败", e);
                }
            }
        }
    }

    /**
     * 提取图号
     */
    private void extractDrawingNumber(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            // 匹配 "图号：" 或 "图号 " 后面的内容
            Pattern.compile("图号[：:\\s]*([\\w\\-\\.]+)", Pattern.CASE_INSENSITIVE),
            // 匹配英文 Drawing No
            Pattern.compile("Drawing\\s*No[：:\\s]*([\\w\\-\\.]+)", Pattern.CASE_INSENSITIVE),
            // 匹配数字格式如 03.021.038504
            Pattern.compile("(\\d{2,}[\\-\\.]\\d{3,}[\\-\\.]\\d{6,})"),
            // 匹配更灵活的图号格式
            Pattern.compile("([A-Z]{2,}[\\-_]\\d{4,}[\\-_]\\d{6,})"),
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String drawingNumber = matcher.group(1).trim();
                if (drawingNumber.length() > 3) {
                    result.setDrawingNumber(drawingNumber);
                    log.debug("提取到图号: {}", drawingNumber);
                    break;
                }
            }
        }
    }

    /**
     * 提取编码
     */
    private void extractCode(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            Pattern.compile("编码[：:\\s]*(\\d{7,})", Pattern.CASE_INSENSITIVE),
            Pattern.compile("Code[：:\\s]*([\\w\\-]+)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("编号[：:\\s]*([\\w\\-]+)"),
            // 匹配长数字编码
            Pattern.compile("(\\d{10,})"),
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String code = matcher.group(1).trim();
                if (code.length() >= 7) {
                    result.setCode(code);
                    log.debug("提取到编码: {}", code);
                    break;
                }
            }
        }
    }

    /**
     * 提取名称 - 优化版
     */
    private void extractName(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            // 匹配 "名称：" 后的中文或英文
            Pattern.compile("名称[：:\\s]*([\\u4e00-\\u9fa5\\w\\s]{2,20})", Pattern.CASE_INSENSITIVE),
            Pattern.compile("Name[：:\\s]*([a-zA-Z\\s]{2,30})", Pattern.CASE_INSENSITIVE),

            // 特殊处理：在图纸中"内齿轮"这样的名称通常出现在特定位置
            Pattern.compile("([\\u4e00-\\u9fa5]{2,8}(?:齿轮|轴|盘|座|套|环|件|零件))"),

            // 匹配材质附近的零件名称
            Pattern.compile("不锈钢\\d+\\s*([\\u4e00-\\u9fa5]{2,8})"),
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String name = matcher.group(1).trim();
                // 去除可能的换行符和多余空格
                name = name.replaceAll("\\s+", "").split("\\n")[0];

                // 过滤无效名称
                Set<String> invalidNames = new HashSet<>(Arrays.asList("名称", "Name", "图号", "编码", "材质"));
                if (name.length() > 1 && name.length() < 20 && !invalidNames.contains(name)) {
                    result.setName(name);
                    log.debug("提取到名称: {}", name);
                    break;
                }
            }
        }
    }

    /**
     * 提取设计者 - 重点优化
     */
    private void extractDesigner(String text, PDFExtractInfoDTO result) {
        log.debug("开始提取设计者，原始文本长度: {}", text.length());

        // 分析文本结构，寻找表格模式
        String[] lines = text.split("\\s+");

        // 方法1: 寻找表格结构中的设计者信息
        for (int i = 0; i < lines.length; i++) {
            if ("更改内容(尺寸、公差、材质等)".equals(lines[i]) || "更改".equals(lines[i])) {
                // 查找紧邻的姓名
                for (int j = i + 1; j < Math.min(i + 10, lines.length); j++) {
                    String candidate = lines[j].trim();
                    if (isValidPersonName(candidate)) {
                        result.setDesigner(candidate);
                        log.debug("方法1提取到设计者: {}", candidate);
                        return;
                    }
                }
            }
        }

//        // 方法2: 分析表格列结构
//        // 根据您的PDF内容，表格结构是：设计者 批准 标准化 工艺 校对
//        Pattern tablePattern = Pattern.compile("设计者\\s+(\\S+)\\s+批准\\s+(\\S+)\\s+标准化\\s+(\\S+)\\s+工艺\\s+(\\S+)\\s+校对\\s+(\\S+)");
//        Matcher tableMatcher = tablePattern.matcher(text);
//        if (tableMatcher.find()) {
//            String designer = tableMatcher.group(1);
//            if (isValidPersonName(designer)) {
//                result.setDesigner(designer);
//                log.debug("方法2提取到设计者: {}", designer);
//                //return;
//            }
//        }
//
//        // 方法3: 寻找姓名+日期的模式
//        Pattern nameWithDatePattern = Pattern.compile("([\\u4e00-\\u9fa5]{2,4})\\s*\\d{4}[-/]\\d{1,2}[-/]\\d{1,2}");
//        Matcher nameWithDateMatcher = nameWithDatePattern.matcher(text);
//        while (nameWithDateMatcher.find()) {
//            String candidate = nameWithDateMatcher.group(1);
//            if (isValidPersonName(candidate)) {
//                result.setDesigner(candidate);
//                log.debug("方法3提取到设计者: {}", candidate);
//               // return;
//            }
//        }
//
//        log.warn("所有方法都未能提取到设计者");
        // 输出调试信息
        debugTableStructure(text);
    }

    /**
     * 验证是否为有效的人名
     */
    private boolean isValidPersonName(String name) {
        if (name == null || name.trim().isEmpty()) return false;
        name = name.trim();

        // 长度检查：中文姓名通常2-4个字符
        if (name.length() < 2 || name.length() > 4) return false;

        // 必须是中文字符
        if (!name.matches("[\\u4e00-\\u9fa5]+")) return false;

        // 排除常见的非人名词汇
        Set<String> excludeWords = new HashSet<>(Arrays.asList(
            "设计", "批准", "标准", "标准化","工艺", "校对", "日期", "材质", "名称",
            "图号", "编码", "重量", "备注", "修订", "更改", "内容", "尺寸",
            "公差", "表面", "粗糙", "锐边", "尖角", "螺纹", "配合", "精度"
        ));

        return !excludeWords.contains(name);
    }

    /**
     * 调试表格结构
     */
    private void debugTableStructure(String text) {
        log.debug("=== 表格结构分析 ===");

        // 寻找包含"设计者"的行
        String[] lines = text.split("\\n");
        for (int i = 0; i < lines.length; i++) {
            if (lines[i].contains("设计者")) {
                log.debug("找到设计者行[{}]: {}", i, lines[i]);
                // 打印前后几行
                for (int j = Math.max(0, i-2); j < Math.min(lines.length, i+3); j++) {
                    log.debug("行[{}]: {}", j, lines[j]);
                }
                break;
            }
        }

        // 分析关键人名
        List<String> chineseNames = extractChineseNames(text);
        log.debug("发现的中文姓名候选: {}", chineseNames);
    }

    /**
     * 提取文本中所有可能的中文姓名
     */
    private List<String> extractChineseNames(String text) {
        List<String> names = new ArrayList<>();
        Pattern namePattern = Pattern.compile("[\\u4e00-\\u9fa5]{2,4}");
        Matcher matcher = namePattern.matcher(text);

        while (matcher.find()) {
            String candidate = matcher.group().trim();
            if (isValidPersonName(candidate)) {
                names.add(candidate);
            }
        }

        return names;
    }

    /**
     * 提取日期信息
     */
    private void extractDates(String text, PDFExtractInfoDTO result) {
        // 通用日期格式
        Pattern datePattern = Pattern.compile("(\\d{4}[-/]\\d{1,2}[-/]\\d{1,2})");
        Matcher dateMatcher = datePattern.matcher(text);

        List<String> dates = new ArrayList<>();
        while (dateMatcher.find()) {
            dates.add(dateMatcher.group(1));
        }

        // 如果找到日期，通常第一个是设计日期
        if (!dates.isEmpty()) {
            result.setDesignDate(dates.get(0));
            log.debug("提取到设计日期: {}", dates.get(0));

            // 如果有多个日期，可能有批准日期
            if (dates.size() > 1) {
                result.setApproveDate(dates.get(dates.size() - 1));
                log.debug("提取到批准日期: {}", dates.get(dates.size() - 1));
            }
        }

        // 尝试更具体的日期提取
        Pattern[] specificPatterns = {
            Pattern.compile("设计.*?(\\d{4}[-/]\\d{1,2}[-/]\\d{1,2})", Pattern.CASE_INSENSITIVE),
            Pattern.compile("批准.*?(\\d{4}[-/]\\d{1,2}[-/]\\d{1,2})", Pattern.CASE_INSENSITIVE),
            Pattern.compile("校对.*?(\\d{4}[-/]\\d{1,2}[-/]\\d{1,2})", Pattern.CASE_INSENSITIVE),
        };

        for (int i = 0; i < specificPatterns.length; i++) {
            Matcher matcher = specificPatterns[i].matcher(text);
            if (matcher.find()) {
                String date = matcher.group(1);
                switch (i) {
                    case 0: result.setDesignDate(date); break;
                    case 1: result.setApproveDate(date); break;
                    case 2: result.setCheckDate(date); break;
                }
            }
        }
    }

    /**
     * 提取材质
     */
    private void extractMaterial(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            Pattern.compile("材质[：:\\s]*([\\w\\d\\u4e00-\\u9fa5]+)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("Material[：:\\s]*([\\w\\d\\s]+)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("材料[：:\\s]*([\\w\\d\\u4e00-\\u9fa5]+)"),
            // 常见材质模式 - 针对不锈钢304等
            Pattern.compile("(不锈钢\\d+|钢\\d+|铝\\w*|铜\\w*|铁\\w*)"),
            // 直接匹配304等材质编号
            Pattern.compile("不锈钢(\\d+)"),
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String material = matcher.group(1).trim();
                if (material.length() > 1 && material.length() < 20) {
                    // 如果只匹配到数字，加上"不锈钢"前缀
                    if (material.matches("\\d+")) {
                        material = "不锈钢" + material;
                    }
                    result.setMaterial(material);
                    log.debug("提取到材质: {}", material);
                    break;
                }
            }
        }
    }

    /**
     * 提取重量 - 优化版
     */
    private void extractWeight(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            Pattern.compile("重量[：/\\s]*(\\d+(?:\\.\\d+)?)[gG]?", Pattern.CASE_INSENSITIVE),
            Pattern.compile("Weight[：/\\s]*(\\d+(?:\\.\\d+)?)[gG]?", Pattern.CASE_INSENSITIVE),
            Pattern.compile("(\\d+(?:\\.\\d+)?)\\s*[gG]"),
            // 匹配更大的数字（可能是重量） - 针对139939这样的值
            Pattern.compile("重量[：/\\s]*(\\d{3,6})"),
            Pattern.compile("/g\\s*(\\d{3,6})"), // 匹配 /g139939 这种格式
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String weight = matcher.group(1).trim();
                result.setWeight(weight + "g");
                log.debug("提取到重量: {}", weight + "g");
                break;
            }
        }
    }

    /**
     * 提取批准人和校对人 - 优化版
     */
    private void extractApproverAndChecker(String text, PDFExtractInfoDTO result) {
        log.debug("开始提取批准人和校对人");

        // 方法1: 直接匹配表格结构
        Pattern tablePattern = Pattern.compile("设计者\\s+(\\S+)\\s+批准\\s+(\\S+)\\s+标准化\\s+(\\S+)\\s+工艺\\s+(\\S+)\\s+校对\\s+(\\S+)");
        Matcher tableMatcher = tablePattern.matcher(text);
        if (tableMatcher.find()) {
            String approver = tableMatcher.group(2);
            String checker = tableMatcher.group(5);

            if (isValidPersonName(approver)) {
                result.setApprover(approver);
                log.debug("表格模式提取到批准人: {}", approver);
            }
            if (isValidPersonName(checker)) {
                result.setChecker(checker);
                log.debug("表格模式提取到校对人: {}", checker);
            }
            return;
        }

        // 方法2: 传统的单独匹配
        // 批准人
//        Pattern[] approverPatterns = {
//            Pattern.compile("批准[：:\\s]*([\\u4e00-\\u9fa5a-zA-Z]{2,10})", Pattern.CASE_INSENSITIVE),
//            Pattern.compile("Approved[：:\\s]*([a-zA-Z\\u4e00-\\u9fa5\\s]+)", Pattern.CASE_INSENSITIVE),
//        };
//
//        for (Pattern pattern : approverPatterns) {
//            Matcher matcher = pattern.matcher(text);
//            if (matcher.find()) {
//                String approver = matcher.group(1).trim();
//                if (isValidPersonName(approver)) {
//                    result.setApprover(approver);
//                    log.debug("传统模式提取到批准人: {}", approver);
//                    break;
//                }
//            }
//        }
//
//        // 校对人
//        Pattern[] checkerPatterns = {
//            Pattern.compile("校对[：:\\s]*([\\u4e00-\\u9fa5a-zA-Z]{2,10})", Pattern.CASE_INSENSITIVE),
//            Pattern.compile("Checked[：:\\s]*([a-zA-Z\\u4e00-\\u9fa5\\s]+)", Pattern.CASE_INSENSITIVE),
//        };
//
//        for (Pattern pattern : checkerPatterns) {
//            Matcher matcher = pattern.matcher(text);
//            if (matcher.find()) {
//                String checker = matcher.group(1).trim();
//                if (isValidPersonName(checker)) {
//                    result.setChecker(checker);
//                    log.debug("传统模式提取到校对人: {}", checker);
//                    break;
//                }
//            }
//        }
        log.debug("批准人和校对人提取完成");
    }

    /**
     * 提取修订版本
     */
    private void extractRevision(String text, PDFExtractInfoDTO result) {
        Pattern[] patterns = {
            Pattern.compile("修订版[：:\\s]*([A-Z\\d]+)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("Revision[：:\\s]*([A-Z\\d]+)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("版本[：:\\s]*([\\d\\.]+)"),
            Pattern.compile("Rev[：:\\s]*([A-Z\\d]+)", Pattern.CASE_INSENSITIVE),
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(text);
            if (matcher.find()) {
                String revision = matcher.group(1).trim();
                if (revision.length() <= 10) {
                    result.setRevision(revision);
                    log.debug("提取到修订版: {}", revision);
                    break;
                }
            }
        }
    }

    /**
     * 提取技术要求 - 优化版
     */
    private void extractTechnicalRequirements(String text, PDFExtractInfoDTO result) {
        List<String> requirements = new ArrayList<>();

        // 查找技术要求部分
        Pattern requirementPattern = Pattern.compile("技术要求[：:\\s]*([\\s\\S]*?)(?=注：|材质|图号|备注|$)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = requirementPattern.matcher(text);

        if (matcher.find()) {
            String requirementText = matcher.group(1).trim();

            // 按数字序号分割技术要求
            String[] lines = requirementText.split("\\s+");
            StringBuilder currentReq = new StringBuilder();

            for (String word : lines) {
                if (word.matches("^\\d+[\\.].*")) {
                    // 如果当前需求不为空，添加到列表
                    if (currentReq.length() > 0) {
                        String req = currentReq.toString().trim();
                        if (req.length() > 5) { // 过滤太短的要求
                            requirements.add(req);
                        }
                        currentReq = new StringBuilder();
                    }
                }
                currentReq.append(word).append(" ");
            }

            // 添加最后一个要求
            if (currentReq.length() > 0) {
                String req = currentReq.toString().trim();
                if (req.length() > 5) {
                    requirements.add(req);
                }
            }
        }

        // 如果上面的方法没有效果，尝试直接查找技术要求关键词
        if (requirements.isEmpty()) {
            Pattern[] directPatterns = {
                Pattern.compile("(未注表面粗糙度按Ra[\\d\\.]+)"),
                Pattern.compile("(未注尺寸公差按GB/T\\d+-\\w+执行)"),
                Pattern.compile("(未注形位公差按GB/T\\d+-\\w+执行)"),
                Pattern.compile("(未注锐边尖角按C[\\d\\.]+倒钝)"),
                Pattern.compile("(螺纹配合精度等级按[\\w/]+)")
            };

            for (Pattern pattern : directPatterns) {
                Matcher directMatcher = pattern.matcher(text);
                while (directMatcher.find()) {
                    requirements.add(directMatcher.group(1));
                }
            }
        }

        result.setTechnicalRequirements(requirements);
        log.debug("提取到{}条技术要求: {}", requirements.size(), requirements);
    }
}
